import * as THREE from "three";
import waterVertexShader from "../shaders/water.vert?raw";
import waterFragmentShader from "../shaders/water.frag?raw";
import { Reflector } from "three/examples/jsm/objects/Reflector.js";

/**@interface WaterOptions {
  environmentMap?: THREE.Texture;
  resolution?: number;
  opacity?: number;
  wavesAmplitude?: number;  
  wavesFrequency?: number;
  wavesPersistence?: number;
  wavesLacunarity?: number;
  wavesIterations?: number;
  wavesSpeed?: number;
  troughColor?: THREE.Color | string | number;
  surfaceColor?: THREE.Color | string | number;
  peakColor?: THREE.Color | string | number;
  peakThreshold?: number;
  peakTransition?: number;
  troughThreshold?: number;
  troughTransition?: number;
  fresnelScale?: number;
  fresnelPower?: number;
  size?: THREE.Vector2;
} */

/**
 * @typedef {Object} WaterOptions
 */
const defaultOptions = {
  resolution: 64,
  opacity: 0.98,
  wavesAmplitude: 0.025,
  wavesFrequency: 1.07,
  wavesPersistence: 0.3,
  wavesLacunarity: 2.18,
  wavesIterations: 8,
  wavesSpeed: new THREE.Vector2(0.1, 0.1),
  troughColor: "#186691",
  surfaceColor: "#9bd8c0",
  peakColor: "#bbd8e0",
  peakThreshold: 0.08,
  peakTransition: 0.05,
  troughThreshold: -0.01,
  troughTransition: 0.15,
  fresnelScale: 1,
  fresnelPower: 0.5,
  size:10,
};

export class Water extends THREE.Mesh {
  /**
   *
   * @param {WaterOptions} options
   */
  constructor(options = {}) {
    const opts = { ...defaultOptions, ...options };
    const textureHeight = 1024;
    const textureWidth = 1024;
    const geometry = new THREE.PlaneGeometry(
      opts.size,
      opts.size,
      opts.resolution ,
      opts.resolution 
    );
    const relector = new Reflector(geometry, {
      textureWidth: textureWidth,
      textureHeight: textureHeight,
      clipBias: 0.003,
    });
    const material = new THREE.ShaderMaterial({
      vertexShader: waterVertexShader,
      fragmentShader: waterFragmentShader,
      uniforms: {
        uTime: { value: 0 },
        uOpacity: { value: opts.opacity },
        uEnvironmentMap: { value: opts.environmentMap },
        uWavesAmplitude: { value: opts.wavesAmplitude },
        uWavesFrequency: { value: opts.wavesFrequency },
        uWavesPersistence: { value: opts.wavesPersistence },
        uWavesLacunarity: { value: opts.wavesLacunarity },
        uWavesIterations: { value: opts.wavesIterations },
        uWavesSpeed: { value: opts.wavesSpeed },
        uTroughColor: { value: new THREE.Color(opts.troughColor) },
        uSurfaceColor: { value: new THREE.Color(opts.surfaceColor) },
        uPeakColor: { value: new THREE.Color(opts.peakColor) },
        uPeakThreshold: { value: opts.peakThreshold },
        uPeakTransition: { value: opts.peakTransition },
        uTroughThreshold: { value: opts.troughThreshold },
        uTroughTransition: { value: opts.troughTransition },
        uFresnelScale: { value: opts.fresnelScale },
        uFresnelPower: { value: opts.fresnelPower },
        reflectMap: { value: relector.getRenderTarget().texture },
        textureMat: {
          value:relector.material.uniforms.textureMatrix.value
      },
    },
      transparent: true,
      depthTest: true,
      side: THREE.DoubleSide,
  });

    super(geometry);

    this.reflector = relector;
    this.material = material;// 为了语法提示
    this.rotation.x = Math.PI * -0.5;
    this.position.y = 0;
  }
  onBeforeRender=(renderer, scene, camera)=> {
    this.visible = false;
    this.reflector.matrixWorld.copy(this.matrixWorld);
    this.reflector.onBeforeRender(renderer, scene, camera);
    this.visible = true;
    // this.refractor.matrixWorld.copy(this.matrixWorld);

    // refractor.onBeforeRender(renderer, scene, camera);
  }

  update(time) {
    this.material.uniforms.uTime.value = time;
  }
}
